<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="robots" content="noodp" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
        <title>《Dart异步编程之Isolate和事件循环》 - Lucklyの博客 - 在阅读中遇见自己</title><meta name="Description" content="早起的年轻人做的网站"><meta property="og:title" content="《Dart异步编程之Isolate和事件循环》" />
<meta property="og:description" content="
本文主要介绍
" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://luckly.work/dart%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8Bisolate%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/" />
<meta property="og:image" content="https://luckly.work/logo.png"/>
<meta property="article:published_time" content="2021-07-31T20:56:14+08:00" />
<meta property="article:modified_time" content="2021-07-31T20:56:14+08:00" />
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="https://luckly.work/logo.png"/>

<meta name="twitter:title" content="《Dart异步编程之Isolate和事件循环》"/>
<meta name="twitter:description" content="
本文主要介绍
"/>
<meta name="application-name" content="LoveIt">
<meta name="apple-mobile-web-app-title" content="LoveIt"><meta name="theme-color" content="#ffffff"><meta name="msapplication-TileColor" content="#da532c"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5"><link rel="manifest" href="/site.webmanifest"><link rel="canonical" href="https://luckly.work/dart%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8Bisolate%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/" /><link rel="prev" href="https://luckly.work/dart%E5%85%A5%E9%97%A8%E7%AC%94%E8%AE%B0/" /><link rel="next" href="https://luckly.work/dart%E4%B9%8B%E7%AC%A8%E5%8A%9E%E6%B3%95%E5%AD%A6dart-dartdoc.dart%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/" /><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.min.css"><link rel="stylesheet" href="/css/style.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.13.0/css/all.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@3.7.2/animate.min.css"><script type="application/ld+json">
    {
        "@context": "http://schema.org",
        "@type": "BlogPosting",
        "headline": "《Dart异步编程之Isolate和事件循环》",
        "inLanguage": "zh-CN",
        "mainEntityOfPage": {
            "@type": "WebPage",
            "@id": "https:\/\/luckly.work\/dart%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8Bisolate%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF\/"
        },"image": [{
                            "@type": "ImageObject",
                            "url": "https:\/\/luckly.work\/images\/Apple-Devices-Preview.png",
                            "width":  3200 ,
                            "height":  2048 
                        }],"genre": "posts","keywords": "flutter","wordcount":  1826 ,
        "url": "https:\/\/luckly.work\/dart%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8Bisolate%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF\/","datePublished": "2021-07-31T20:56:14+08:00","dateModified": "2021-07-31T20:56:14+08:00","license": "This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.","publisher": {
            "@type": "Organization",
            "name": "xxxx","logo": {
                    "@type": "ImageObject",
                    "url": "https:\/\/luckly.work\/images\/avatar.png",
                    "width":  528 ,
                    "height":  560 
                }},"author": {
                "@type": "Person",
                "name": "早起的年轻人"
            },"description": ""
    }
    </script></head>
    <body header-desktop="fixed" header-mobile="auto"><script type="text/javascript">(window.localStorage && localStorage.getItem('theme') ? localStorage.getItem('theme') === 'dark' : ('auto' === 'auto' ? window.matchMedia('(prefers-color-scheme: dark)').matches : 'auto' === 'dark')) && document.body.setAttribute('theme', 'dark');</script>

        <div id="mask"></div><div class="wrapper"><div class="logo-wrapper">
  <a href="/%20/" class="logo">Lucklyの博客 - 在阅读中遇见自己</a>
</div>

<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
      <a class="menu-item-link" href="/posts/">所有文章</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/categories/flutter/">Flutter</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/categories/read/">读书笔记</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/categories/go/">Go</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/tags/">标签</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/categories/">分类</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/about/">关于</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="https://github.com/ITmxs">Github</a>
    </li><li class="menu-item">
      <a class="menu-item-link" href="/friend/">友链</a>
    </li>
  </ul>
</nav><main class="main">
                <div class="container"><div class="toc" id="toc-auto">
            <h2 class="toc-title">目录</h2>
            <div class="toc-content" id="toc-content-auto"></div>
        </div><article class="page single"><h1 class="single-title animated flipInX">《Dart异步编程之Isolate和事件循环》</h1><div class="post-meta">
            <div class="post-meta-line"><span class="post-author"><a href="/" title="Author" rel=" author" class="author"><i class="fas fa-user-circle fa-fw"></i>早起的年轻人</a></span>&nbsp;<span class="post-category">收录于 <a href="/categories/flutter/"><i class="far fa-folder fa-fw"></i>Flutter</a></span></div>
            <div class="post-meta-line"><i class="far fa-calendar-alt fa-fw"></i>&nbsp;<time datetime="2021-07-31">2021-07-31</time>&nbsp;<i class="fas fa-pencil-alt fa-fw"></i>&nbsp;约 1826 字&nbsp;
                <i class="far fa-clock fa-fw"></i>&nbsp;预计阅读 4 分钟&nbsp;</div>
        </div><div class="featured-image"><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png, https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png"
        title="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png" /></div><div class="details toc" id="toc-static"  kept="">
                <div class="details-summary toc-title">
                    <span>目录</span>
                    <span><i class="details-icon fas fa-angle-right"></i></span>
                </div>
                <div class="details-content toc-content" id="toc-content-static"><nav id="TableOfContents">
  <ul>
    <li><a href="#isolates">Isolates</a></li>
    <li><a href="#event-loops">Event loops</a></li>
    <li><a href="#总结">总结</a></li>
  </ul>
</nav></div>
            </div><div class="content" id="content"><blockquote>
<p>本文主要介绍</p>
</blockquote>
<p>Dart 异步编程之 Isolate 和事件循环。编译自 <a href="https://medium.com/dartlang/dart-asynchronous-programming-isolates-and-event-loops-bffc3e296a6a" target="_blank" rel="noopener noreffer">Dart asynchronous programming: Isolates and event loops</a>。</p>
<p>尽管 Dart 是个单线程任务，但它提供 Future、Stream、后台任务以及其他特性用于编写现代异步程序以及响应式程序(Flutter)。本文讲的是 Dart 后台任务的基础：Isolate 和事件循环。</p>
<p>如果你倾向于通过视频学习，可以在以下视频中找到本文讲解的内容。这个视频是 the Flutter in Focus 系列的一部分《Dart 中的异步编程》：</p>
<p>Still here? Let’s talk about isolates.</p>
<p>我们先从 Isolate 开始。</p>
<h1 id="isolates">Isolates</h1>
<hr>
<p>译者补充：</p>
<blockquote>
<p>大多数应用程序中，线程的数量都不止一个。多个线程可以互不干扰地并发执行，并共享进程的全局变量和堆的数据。
线程的访问非常自由，它可以访问进程内存里的所有数据，甚至包括其他线程的堆栈
《程序员的自我修养》</p>
</blockquote>
<hr>
<p>所有的 Dart 代码都运行在 Isolate 中。Isolate 有自己私有的内存空间和一个基于事件循环的线程。</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg"
        title="Two isolates, each with its own memory and thread of execution." /></p>
<p>在其他很多语言中，比如 C++，多个线程可运行任何代码并共享内存。但 Dart 中每个线程在其自己的 Isolate 中，有自己的内存，线程只处理事件(后面很快会详细展开)。</p>
<p>大部分 Dart 应用在一个 Isolate 中运行全部代码，也可以根据需要创建更多 Isolate。如果某个操作计算量如此之大以至于它在主 Isolate 运行中会导致掉帧，可以使用 <a href="https://api.dartlang.org/stable/dart-isolate/Isolate/spawn.html" target="_blank" rel="noopener noreffer">Isolate.spawn()</a> 或<a href="https://flutter.dev/docs/cookbook/networking/background-parsing#4-move-this-work-to-a-separate-isolate" target="_blank" rel="noopener noreffer">Flutter’s compute() function</a> 方法。这些方法都会创建独立的 Isolate 来做密集计算，让主 Isolate 专注重建和渲染 Widget 树。</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747512192242.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747512192242.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747512192242.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747512192242.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747512192242.jpg"
        title="Two isolates, each with its own memory and thread of execution." /></p>
<p>新创建的 Isolate 有自己的事件循环和内存，原先的 Isolate (即创建新 Isolate 的那个 Isolate) 不能访问这些内存。这种机制正是 Isolate 名字的来源：内存块之间彼此<strong>隔离</strong>。</p>
<p>事实上，Isolate 之间能协作的唯一方式是消息传递。一个 Isolate 可以向另一个 Isolate 发送消息，接收方在其事件循环处理收到的消息。</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg"
        title="Isolates can send messages to other isolates." /></p>
<p>缺少共享内存听起来过于严格，尤其是你之前用过 Java 或 C++，但它给 Dart 开发者带来一些重要的好处。</p>
<p>比如，Isolate 中内存分配和垃圾回收不需要锁定。Isolate 中只有一个线程，如果它不是很忙的话，内存并不会快速变化，所以不必锁定。这非常适合 Flutter 应用，它时常要迅速地构建和销毁 Widget 树。</p>
<h1 id="event-loops">Event loops</h1>
<p>现在你已经了解 Isolate 了，再来看看事件循环是如何让异步代码变成可能的吧。</p>
<p>想像一下应用沿着时间线的运行过程。应用启动，应用停止，之间发生一串串事件：磁盘 IO，用户手势以及类似一些事件。</p>
<p>应用无法预测事件何时发生、以何种顺序发生，它必须在单个线程中处理所有事件并且保证不阻塞。所以应用会运行一个事件循环。它从事件队列中取出最老的事件进行处理，然后再取下一个事件，依次进行，直到事件队列为空。</p>
<p>应用一直在运行：你点击屏幕、下载数据、触发定时器。事件循环一直在运行，每次处理一个事件。</p>
<p><img
        class="lazyload"
        src="/svg/loading.min.svg"
        data-src="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg"
        data-srcset="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg 1.5x, https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg 2x"
        data-sizes="auto"
        alt="https://luckly007.oss-cn-beijing.aliyuncs.com/img/15747423247738.jpg"
        title="The event loop processes one event at a time." /></p>
<p>事件循环空闲时，线程会暂停并循环下一个事件。这时可能触发垃圾回收器等等。Dart 为异步编程提供的所有高级 API 和语言特性，如 Future、Stream、<code>async/await</code>，都是基于和围绕这个基本的循环。</p>
<p>比如，某个按钮用于发起网络请求，就像这样：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">RaisedButton(
  child: Text(&#39;Click me&#39;),
  onPressed: () {
    final myFuture = http.get(&#39;https://example.com&#39;);
    myFuture.then((response) {
      if (response.statusCode == 200) {
        print(&#39;Success!&#39;);
      }
    });
  },
)
</code></pre></td></tr></table>
</div>
</div><p>你运行应用时，Flutter 构建按钮并显示到屏幕，之后应用开始等待。</p>
<p>应用的事件循环处于空闲，等待下一个事件。当按钮等待点击时，跟按钮不相关的事件可能发生并进入到事件队列被处理。当点击事件发生时，最终会进入队列。</p>
<p>点击事件被取到，等待处理。Flutter 看到这个事件，它的渲染系统说 “事件坐标跟 RaisedButton 匹配”，所以 Flutter 执行 <code>onPressed</code> 函数。这个函数会发起网络请求(返回一个 Future)并使用 <code>then()</code> 方法注册 completion handler。</p>
<p>整个过程就是这样的。事件循环处理完点击事件后将其抛弃。</p>
<p><code>onPressed</code> 是 <a href="https://api.flutter.dev/flutter/material/RaisedButton-class.html" target="_blank" rel="noopener noreffer">RaisedButton</a> 的一个属性，而网络事件为 Future 添加了一个回调，但两者都是在相同的基本操作。它们都是在告诉 Flutter，”你好，一会儿将发生某个事件，你记得执行该事件的代码。”</p>
<p><code>onPressed</code> 在等待点击，而 Future 在等待网络数据，从 Dart 的视角，这些都是队列中的事件。</p>
<p>这也正是 Dart 中异步代码的工作方式。Future、Steam、以及 <code>async/await</code>，这些 API 都是你告诉 Dart 事件循环执行代码的一种方式。</p>
<p>如果再来回头看刚才的例子，你可以准确地看到它是如何为特定的事件被分解成一小块一小块的。</p>
<ol>
<li>初始的 UI 构建事件</li>
<li>点击事件</li>
<li>网络响应事件</li>
</ol>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre class="chroma"><code class="language-fallback" data-lang="fallback">RaisedButton( // (1)
  child: Text(&#39;Click me&#39;),
  onPressed: () { // (2)
    final myFuture = http.get(&#39;https://example.com&#39;);
    myFuture.then((response) { // (3)
      if (response.statusCode == 200) {
        print(&#39;Success!&#39;);
      }
    });
  },
)
</code></pre></td></tr></table>
</div>
</div><p>你习惯异步代码之后，到处都可以看到这些模式。理解事件循环对你跟高级 API 打交道时同样有帮助。</p>
<h1 id="总结">总结</h1>
<p>我们简单地了解了 Dart 中的 Isolate、事件循环以及异步编程基础。</p>
<p>如果你想了解更多，请看这个关于异步编程的视频。它讨论的是 Future API，这个 API 用于简化异步程序代码。</p></div><div class="post-footer" id="post-footer">
    <div class="post-info">
        <div class="post-info-line">
            <div class="post-info-mod">
                <span>更新于 2021-07-31</span>
            </div>
            <div class="post-info-license"></div>
        </div>
        <div class="post-info-line">
            <div class="post-info-md"></div>
            <div class="post-info-share">
                <span><a href="javascript:void(0);" title="分享到 Twitter" data-sharer="twitter" data-url="https://luckly.work/dart%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8Bisolate%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/" data-title="《Dart异步编程之Isolate和事件循环》" data-hashtags="flutter"><i class="fab fa-twitter fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Facebook" data-sharer="facebook" data-url="https://luckly.work/dart%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8Bisolate%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/" data-hashtag="flutter"><i class="fab fa-facebook-square fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Hacker News" data-sharer="hackernews" data-url="https://luckly.work/dart%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8Bisolate%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/" data-title="《Dart异步编程之Isolate和事件循环》"><i class="fab fa-hacker-news fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Line" data-sharer="line" data-url="https://luckly.work/dart%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8Bisolate%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/" data-title="《Dart异步编程之Isolate和事件循环》"><i data-svg-src="https://cdn.jsdelivr.net/npm/simple-icons@2.14.0/icons/line.svg"></i></a><a href="javascript:void(0);" title="分享到 微博" data-sharer="weibo" data-url="https://luckly.work/dart%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E4%B9%8Bisolate%E5%92%8C%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/" data-title="《Dart异步编程之Isolate和事件循环》" data-image="https://luckly007.oss-cn-beijing.aliyuncs.com/img/90c6cc12-742e-4c9f-b318-b912f163b8d0.png"><i class="fab fa-weibo fa-fw"></i></a></span>
            </div>
        </div>
    </div>

    <div class="post-info-more">
        <section class="post-tags"><i class="fas fa-tags fa-fw"></i>&nbsp;<a href="/tags/flutter/">flutter</a></section>
        <section>
            <span><a href="javascript:void(0);" onclick="window.history.back();">返回</a></span>&nbsp;|&nbsp;<span><a href="/">主页</a></span>
        </section>
    </div>

    <div class="post-nav"><a href="/dart%E5%85%A5%E9%97%A8%E7%AC%94%E8%AE%B0/" class="prev" rel="prev" title="《Dart入门笔记》"><i class="fas fa-angle-left fa-fw"></i>《Dart入门笔记》</a>
            <a href="/dart%E4%B9%8B%E7%AC%A8%E5%8A%9E%E6%B3%95%E5%AD%A6dart-dartdoc.dart%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/" class="next" rel="next" title="《Dart之笨办法学Dart Dartdoc">《Dart之笨办法学Dart Dartdoc<i class="fas fa-angle-right fa-fw"></i></a></div>
</div>
</article></div>
            </main><footer class="footer">
        <div class="footer-container"><div class="footer-line">由 <a href="https://gohugo.io/" target="_blank" rel="noopener noreffer" title="Hugo 0.79.1">Hugo</a> 强力驱动 | 主题 - <a href="https://github.com/dillonzq/LoveIt" target="_blank" rel="noopener noreffer" title="LoveIt 0.2.10"><i class="far fa-kiss-wink-heart fa-fw"></i> LoveIt</a>
                </div><div class="footer-line"><i class="far fa-copyright fa-fw"></i><span itemprop="copyrightYear">2021</span><span class="author" itemprop="copyrightHolder">&nbsp;<a href="/" target="_blank">早起的年轻人</a></span>&nbsp;|&nbsp;<span class="license"><a rel="license external nofollow noopener noreffer" href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank">CC BY-NC 4.0</a></span></div>
        </div>
    </footer></div>

        <div id="fixed-buttons"><a href="#" id="back-to-top" class="fixed-button" title="回到顶部">
                <i class="fas fa-arrow-up fa-fw"></i>
            </a><a href="#" id="view-comments" class="fixed-button" title="查看评论">
                <i class="fas fa-comment fa-fw"></i>
            </a>
        </div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cookieconsent@3.1.1/build/cookieconsent.min.css"><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/smooth-scroll@16.1.3/dist/smooth-scroll.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/autocomplete.js@0.37.1/dist/autocomplete.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/algoliasearch@4.2.0/dist/algoliasearch-lite.umd.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lazysizes@5.2.2/lazysizes.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/clipboard@2.0.6/dist/clipboard.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/sharer.js@0.4.0/sharer.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/cookieconsent@3.1.1/build/cookieconsent.min.js"></script><script type="text/javascript">window.config={"code":{"copyTitle":"复制到剪贴板","maxShownLines":10},"comment":{},"cookieconsent":{"content":{"dismiss":"同意","link":"了解更多","message":"本网站使用 Cookies 来改善您的浏览体验."},"enable":true,"palette":{"button":{"background":"#f0f0f0"},"popup":{"background":"#1aa3ff"}},"theme":"edgeless"},"search":{"algoliaAppID":"PASDMWALPK","algoliaIndex":"index.zh-cn","algoliaSearchKey":"b42948e51daaa93df92381c8e2ac0f93","highlightTag":"em","maxResultLength":10,"noResultsFound":"没有找到结果","snippetLength":50,"type":"algolia"}};</script><script type="text/javascript" src="/js/theme.min.js"></script></body>
</html>
